#include "config.h" 
#include "debug.h"
#include "iot2.h"
#include "at_com.h"
#include "callback.h"

#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "queue.h"

#include "string.h"
#include "stdlib.h"

u8 TxBuffer1[128] = {0};

ROUTE_ITEM g_route_arr[] = {
    {"CONNECTED", proc_rx_msg_connected},
    {"OK", proc_rx_msg_ok},
};

SemaphoreHandle_t g_wait_ok_mtx;
volatile WAIT_OK g_wait_ok = {
    .is_waiting_ = pdFALSE,
    .tick_ = 0,
    .timeout_ms_ = 0
};

USART_DMA_CTRL g_usart_dma_ctrl = {
    .DMA_USE_BUFFER = 0,
    .Rx_Buffer = {0},
};

RING_BUFFER g_ring_buffer = {{0}, 0, 0, 0};

QueueHandle_t iot_rx_line_que;

QueueHandle_t iot_rx_topic_que;

SemaphoreHandle_t g_ring_buffer_mtx;

// USART3, TX:PB10; RX:PB11
void USART3_IRQHandler(void) __attribute__((interrupt()));
void DMA1_Channel3_IRQHandler(void) __attribute__((interrupt()));
void DMA1_Channel2_IRQHandler(void) __attribute__((interrupt()));

void USART3_IRQHandler(void)
{
  if (USART_GetITStatus(USART3, USART_IT_IDLE) != RESET)
  {
//    xSemaphoreTakeFromISR(g_usart_dma_ctrl_mtx, NULL);
    // IDLE
    uint16_t rxlen = (RX_BUFFER_LEN - USART_RX_CH->CNTR);
    uint8_t oldbuffer = g_usart_dma_ctrl.DMA_USE_BUFFER;
    
    g_usart_dma_ctrl.DMA_USE_BUFFER = !oldbuffer;

    DMA_Cmd(USART_RX_CH, DISABLE);
    DMA_SetCurrDataCounter(USART_RX_CH, RX_BUFFER_LEN);
    // Switch buffer
    USART_RX_CH->MADDR = (uint32_t)(g_usart_dma_ctrl.Rx_Buffer[g_usart_dma_ctrl.DMA_USE_BUFFER]);
    DMA_Cmd(USART_RX_CH, ENABLE);

    USART_ReceiveData(USART3); // clear IDLE flag
    ring_buffer_push_huge(g_usart_dma_ctrl.Rx_Buffer[oldbuffer], rxlen);
//    xSemaphoreGiveFromISR(g_usart_dma_ctrl_mtx, NULL);
  }
}

void DMA1_Channel3_IRQHandler(void)
{
//    xSemaphoreTakeFromISR(g_usart_dma_ctrl_mtx, NULL);
    uint16_t rxlen     = RX_BUFFER_LEN;
    uint8_t  oldbuffer = g_usart_dma_ctrl.DMA_USE_BUFFER;
    // FULL

    g_usart_dma_ctrl.DMA_USE_BUFFER = !oldbuffer;

    DMA_Cmd(USART_RX_CH, DISABLE);
    DMA_SetCurrDataCounter(USART_RX_CH, RX_BUFFER_LEN);
    // Switch buffer
    USART_RX_CH->MADDR = (uint32_t)(g_usart_dma_ctrl.Rx_Buffer[g_usart_dma_ctrl.DMA_USE_BUFFER]);
    DMA_Cmd(USART_RX_CH, ENABLE);

    ring_buffer_push_huge(g_usart_dma_ctrl.Rx_Buffer[oldbuffer], rxlen);
//    xSemaphoreGiveFromISR(g_usart_dma_ctrl_mtx, NULL);

    DMA_ClearITPendingBit(DMA1_IT_TC3);
}

void DMA1_Channel2_IRQHandler(void)
{
    // GPIO_WriteBit(GPIOE, GPIO_Pin_5, ~GPIO_ReadOutputDataBit(GPIOE,GPIO_Pin_5));
    // DMA_ClearITPendingBit(DMA1_IT_TC2);
}

// USART3, TX:PB10; RX:PB11
void iot_hal_init()
{
  g_ring_buffer_mtx = xSemaphoreCreateMutex();
    g_wait_ok_mtx = xSemaphoreCreateMutex();
    // g_usart_dma_ctrl_mtx = xSemaphoreCreateMutex();
    iot_rx_line_que = xQueueCreate(3, sizeof(LINE_BUFFER));
    iot_rx_topic_que = xQueueCreate(3, sizeof(TOPIC_BUFFER));
    // HAL
    GPIO_InitTypeDef  GPIO_InitStructure={0};
    USART_InitTypeDef USART_InitStructure={0};
    NVIC_InitTypeDef  NVIC_InitStructure={0};
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    // USART3_RM=0, TX/RX=PA2/PA3; =1, TX/RX=PD5/PD6
    // GPIO_PinRemapConfig(GPIO_PartialRemap_USART3, DISABLE);

    // PB9, PB8
    // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_8;
    // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    // GPIO_Init(GPIOB, &GPIO_InitStructure);

    /* USART3 TX-->A.2   RX-->A.3 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    // PB13/PB12 => 1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOB, &GPIO_InitStructure);

    USART_InitStructure.USART_BaudRate = 115200;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART3, &USART_InitStructure);
    // USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART3, USART_IT_IDLE, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    USART_Cmd(USART3, ENABLE);

    DMA_INIT();
}

void DMA_INIT(void)
{
    DMA_InitTypeDef  DMA_InitStructure  = {0};
    NVIC_InitTypeDef NVIC_InitStructure = {0};

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

    DMA_DeInit(USART_TX_CH);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DATAR); /* USART3->DATAR:0x40004404 */
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)TxBuffer1;
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
    DMA_InitStructure.DMA_BufferSize = TxSize1;
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    DMA_Init(USART_TX_CH, &DMA_InitStructure);

    DMA_DeInit(USART_RX_CH);
    DMA_InitStructure.DMA_PeripheralInc      = DMA_PeripheralInc_Disable;
    DMA_InitStructure.DMA_MemoryInc          = DMA_MemoryInc_Enable;
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
    DMA_InitStructure.DMA_MemoryDataSize     = DMA_MemoryDataSize_Byte;
    DMA_InitStructure.DMA_Mode               = DMA_Mode_Normal;
    DMA_InitStructure.DMA_Priority           = DMA_Priority_VeryHigh;
    DMA_InitStructure.DMA_M2M                = DMA_M2M_Disable;

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)(&USART3->DATAR);
    DMA_InitStructure.DMA_MemoryBaseAddr     = (u32)g_usart_dma_ctrl.Rx_Buffer[0];
    DMA_InitStructure.DMA_DIR                = DMA_DIR_PeripheralSRC;
    DMA_InitStructure.DMA_BufferSize         = RX_BUFFER_LEN;
    DMA_Init(USART_RX_CH, &DMA_InitStructure);

    DMA_ITConfig(USART_RX_CH, DMA_IT_TC, ENABLE);
    // DMA_ITConfig(USART_TX_CH, DMA_IT_TC, ENABLE);

    NVIC_InitStructure.NVIC_IRQChannel                   = DMA1_Channel3_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // NVIC_InitStructure.NVIC_IRQChannel                   = DMA1_Channel2_IRQn;
    // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 5;
    // NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    // NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    // NVIC_Init(&NVIC_InitStructure);

    DMA_Cmd(USART_RX_CH, ENABLE);
    DMA_Cmd(USART_TX_CH, ENABLE);
    // USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
}

void reset_wait_OK(WAIT_OK *pw) 
{
    pw->is_waiting_ = pdFALSE;
    pw->result_ = 0;
    pw->tick_ = 0;
    pw->timeout_ms_ = 0;
}

int waiting_OK(int timeout_ms) {
  g_wait_ok.is_waiting_ = pdTRUE;
  g_wait_ok.result_ = 0;
  g_wait_ok.tick_ = xTaskGetTickCount();
  g_wait_ok.timeout_ms_ = timeout_ms;

  int ret = AT_ERRNO_OK;
  TickType_t delta = 0;
  int res = 0;
  while ((delta = xTaskGetTickCount() - g_wait_ok.tick_) <=
         pdMS_TO_TICKS(g_wait_ok.timeout_ms_)) {
    if (xSemaphoreTake(g_wait_ok_mtx, pdMS_TO_TICKS(10)) == pdTRUE) {
      g_wait_ok.is_waiting_ = pdTRUE;
      res = g_wait_ok.result_;  // g_wait_ok.result_只能由proc_rx_line()函数修改
      xSemaphoreGive(g_wait_ok_mtx);
    } else {
      printf("xSemaphoreTake(g_wait_ok_mtx) => FALSE\r\n");
    }
    if (res == 1) {
      ret = AT_ERRNO_OK;
      break;
    }
    vTaskDelay(pdMS_TO_TICKS(50));
  }
  g_wait_ok.is_waiting_ = pdFALSE;
  if (delta > pdMS_TO_TICKS(g_wait_ok.timeout_ms_)) {
    ret = AT_ERRNO_TIMEOUT;
  }
  return ret;
}

void ring_buffer_push_huge(uint8_t *buffer, uint16_t len)
{
  // xSemaphoreTakeFromISR(g_ring_buffer_mtx, NULL);
  const uint16_t bufferRemainCount = RING_BUFFER_LEN -  g_ring_buffer.RemainCount;
  if (bufferRemainCount < len)
  {
      len = bufferRemainCount;
  }

  const uint16_t bufferSize = RING_BUFFER_LEN - g_ring_buffer.RecvPos;
  if (bufferSize >= len)
  {
      memcpy(&(g_ring_buffer.buffer[g_ring_buffer.RecvPos]), buffer, len);
      g_ring_buffer.RecvPos += len;

      g_ring_buffer.RemainCount += len;
  }
  else
  {
    memcpy(g_ring_buffer.buffer, buffer, len);
    g_ring_buffer.RecvPos = len;
    g_ring_buffer.RemainCount = len;
      // uint16_t otherSize = len - bufferSize;
      // memcpy(&(g_ring_buffer.buffer[g_ring_buffer.RecvPos]), buffer, bufferSize);
      // memcpy(g_ring_buffer.buffer, &(buffer[bufferSize]), otherSize);
      // g_ring_buffer.RecvPos = otherSize;
  }
  // xSemaphoreGiveFromISR(g_ring_buffer_mtx, NULL);
}

uint8_t ring_buffer_pop()
{
    uint8_t data = g_ring_buffer.buffer[g_ring_buffer.SendPos];

    g_ring_buffer.SendPos++;
    if (g_ring_buffer.SendPos >= RING_BUFFER_LEN)
    {
        g_ring_buffer.SendPos = 0;
    }
    g_ring_buffer.RemainCount--;
    return data;
}

uint8_t ring_buffer_peek()
{
    return g_ring_buffer.buffer[g_ring_buffer.SendPos];
}

void xy_at_uart_input_byte(at_agent_t *pat_agent, uint8_t data)
{
    if (pat_agent->uart_rx_fifo_len + 1  < pat_agent->uart_rx_fifo_len_max) {
        pat_agent->uart_rx_fifo_buffer[pat_agent->uart_rx_fifo_len++] = data;
    }
}

int get_relay_val_from_str(const char* str)
{
  int res = 0;
  int len = strlen(str);
  int i = 0;
  for (i = 0; i < len; i++) {
    if (str[i] == ':' && (i+1) < len) {
      i = i+1;
      break;
    }
  }
  if (i == len)
    return 0;
  
  char *pch = &str[i];
  len = strlen(pch);
  if (pch[len - 1] == '}') {
    pch[len - 1] = '\0';
  }
  // printf("val_str: %s\n", pch);
  return atoi(pch);
}

void iot_task_entry(void *pvParameters)
{
    (void)pvParameters;
    uint16_t remain_count = 0;
    GPIO_WriteBit(GPIOB, GPIO_Pin_12, 1);
    GPIO_WriteBit(GPIOB, GPIO_Pin_13, 1);
    printf("iot_task_entry start...\n");
    USART_DMACmd(USART3, USART_DMAReq_Rx, ENABLE);
    for( ;; ) 
    {
      {
      remain_count = g_ring_buffer.RemainCount;
      // remain_count = g_ring_buffer.RecvPos - g_ring_buffer.SendPos;
      if (remain_count > 2) {
        volatile int16_t i = 0, len = 0, real_len = 0;
        volatile uint8_t is_found_line_break = 0;
//        printf("sendPos:%u, recvPos:%u, remain_count:%u\n",
//               g_ring_buffer.SendPos, g_ring_buffer.RecvPos, remain_count);

        // FIXME: 当串口输入满一环时, 调整遍历游标;使SendPos < RecvPos一直成立
        if (g_ring_buffer.SendPos > g_ring_buffer.RecvPos) {
          g_ring_buffer.SendPos = 0;
        }

        for (i = g_ring_buffer.SendPos;
             i < g_ring_buffer.SendPos + remain_count && i < RING_BUFFER_LEN;
             i++) {
          if (g_ring_buffer.buffer[i] == '\n') {
            is_found_line_break = 1;
            real_len++;
            if (i - 1 >= 0 && g_ring_buffer.buffer[i - 1] == '\r') {
              len--;
            }
            break;
          } else {
            len++;
            real_len++;
          }
        }
        // 如果找不到'\n'则跳出循环并休息
        if (is_found_line_break == 0) {
          vTaskDelay(500);
          continue;
        }

        // for (i = g_ring_buffer.SendPos; i <  g_ring_buffer.SendPos +
        // real_len; i++) { if (g_ring_buffer.buffer[i] == 0x0D ||
        // g_ring_buffer.buffer[i] == 0x0A) {
        //     printf("!!![%d]%X\n", i, g_ring_buffer.buffer[i]);
        //     // while(1);
        // }
        //     printf("%02X ", g_ring_buffer.buffer[i]);
        // }
        // printf("\n");

        // if (len == 0) {
        //     printf("sendPos:%u, recvPos:%u, remain_count:%u, len:%u,
        //     real_len:%u\n",
        //            g_ring_buffer.SendPos, g_ring_buffer.RecvPos,
        //            remain_count, len, real_len);
        // }

        // FIXME: 纯"'\r\n"会导致程序跑飞!!!
        if (len == 0) {
          while (real_len > 0) {
            ring_buffer_pop();
            real_len--;
          }
          continue;
        }

        LINE_BUFFER lbuf;
        lbuf.len = len;
        lbuf.pbuf = (char *)pvPortMalloc(len);
        if (lbuf.pbuf == NULL) {
          printf("pvPortMalloc() => NULL");
          return;
        }
        //            printf("req mem:%u byte successfully\n", len);
        i = 0;
        while (i < real_len) {
          if (i < len)
            lbuf.pbuf[i] = ring_buffer_pop();
          else
            ring_buffer_pop();  // 将"\r\n"都释放掉

          i++;
        }
        xSemaphoreGive(g_ring_buffer_mtx);
        if (xQueueSend(iot_rx_line_que, &lbuf, 0) != pdTRUE) {
          printf("queue max!\n");
          vPortFree(lbuf.pbuf);
        }
      }
      }
      vTaskDelay(pdMS_TO_TICKS(1));
    }
}

// 
void iot_monitor_task_entry(void *pvParameters)
{
  (void)pvParameters;
  LINE_BUFFER lbuf;
  memset(&lbuf, 0, sizeof(LINE_BUFFER));
  for ( ;; ) 
  {
      if (xQueueReceive(iot_rx_line_que, &lbuf, portMAX_DELAY) == pdTRUE) {
//          printf("(%X)[%d]:", (void *)lbuf.pbuf, lbuf.len);
//          for (int i = 0; i < lbuf.len; i++) {
//            // printf("%02X ", (uint16_t)lbuf.pbuf[i]);
//            putchar(lbuf.pbuf[i]);
//          }
//          putchar('\n');

        proc_rx_line(lbuf.pbuf, lbuf.len);

        vPortFree(lbuf.pbuf);
        lbuf.pbuf = NULL;
        lbuf.len = 0;
      } else {
        printf("iot_monitor_task_entry timeout\n");
      }
      vTaskDelay(pdMS_TO_TICKS(100));
  }
}
